/*
 * Copyright 2010 Alessandro Bellucci
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.soupframework.gwt.designerpanel.client.designer.impl.widget;

import org.soupframework.gwt.designerpanel.client.DesignerPanel;
import org.soupframework.gwt.designerpanel.client.designer.ContainerDesigner;
import org.soupframework.gwt.designerpanel.client.designer.Designer;
import org.soupframework.gwt.designerpanel.client.designer.DesignerManager;
import org.soupframework.gwt.designerpanel.client.designer.impl.DesignerManagerBase;
import org.soupframework.gwt.designerpanel.client.event.ChildDesignerAddedEvent;
import org.soupframework.gwt.designerpanel.client.event.ObjectAddedEvent;
import org.soupframework.gwt.designerpanel.client.event.ObjectAddedEventHandler;

import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.CaptionPanel;
import com.google.gwt.user.client.ui.ComplexPanel;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.FocusPanel;
import com.google.gwt.user.client.ui.HorizontalPanel;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SimplePanel;
import com.google.gwt.user.client.ui.VerticalPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * Out of the box implementation for {@link DesignerManager}
 *
 * @param <T> represents the base type of the objects being designed
 */
public class WidgetDesignerManager extends DesignerManagerBase<Widget> {

	public WidgetDesignerManager(DesignerPanel<Widget> designerPanel){
		super(designerPanel);
	}

	/**
	 * Design the given {@link Widget}
	 *
	 * @param object the object
	 */
	@SuppressWarnings("unchecked")
	@Override
	protected Designer<Widget> design(ContainerDesigner<Widget> parent, Widget object) {
		final Designer<Widget> d = getDesigner(parent, object);
		if(parent != null && d != null){
			parent.addChildDesigner(d);
		}

		// Register child designers when new widget are added in the future
		if(d instanceof ContainerDesigner){
			((ContainerDesigner<Widget>)d).addObjectAddedHandler(new ObjectAddedEventHandler<Widget>() {
				@Override
				public void onObjectAdded(ObjectAddedEvent<Widget> event) {
					Widget childObject = event.getAddedObject();
					design((ContainerDesigner<Widget>)d, childObject);
				}
			});
		}

		// Register child designers for children widgets
		if(object instanceof SimplePanel) {
			SimplePanel sp = (SimplePanel)object;
			if(sp.getWidget() != null) {
				this.design((ContainerDesigner)d, sp.getWidget());
			}
		}
		else if(object instanceof ComplexPanel) {
			ComplexPanel cp = (ComplexPanel)object;
			for(int i = 0 ; i < cp.getWidgetCount() ; i ++) {
				this.design((ContainerDesigner)d, cp.getWidget(i));
			}
		}
		else if(object instanceof CaptionPanel) {
			CaptionPanel cp = (CaptionPanel)object;
			if(cp.getContentWidget() != null) {
				this.design((ContainerDesigner<Widget>)d, cp.getContentWidget());
			}
		}
		else if(object instanceof HorizontalPanel) {
			HorizontalPanel hp = (HorizontalPanel)object;
			for(int i = 0 ; i < hp.getWidgetCount() ; i ++) {
				this.design((ContainerDesigner)d, hp.getWidget(i));
			}
		}
		else if(object instanceof VerticalPanel) {
			VerticalPanel hp = (VerticalPanel)object;
			for(int i = 0 ; i < hp.getWidgetCount() ; i ++) {
				this.design((ContainerDesigner)d, hp.getWidget(i));
			}
		}
		return d;
	}

	/**
	 * Gets the {@link Designer} for the given object
	 *
	 * @param object the object
	 * @return the {@link Designer}
	 */
	protected Designer<Widget> getDesigner(ContainerDesigner<Widget> parent, Widget object) {
		Designer<Widget> d = this.designers.get(object);
		if(d == null) {
			d = createDesigner(parent, object);
			if(d != null) {
				this.designers.put(object, d);
			}

			if(parent != null){
				parent.fireEvent(new ChildDesignerAddedEvent<Widget>(d));
			}
		}
		return d;
	}

	/**
	 * Creates a designer for the given object
	 *
	 * @param object the object
	 * @return the {@link Designer} for object
	 */
	protected Designer<Widget> createDesigner(ContainerDesigner<Widget> parent, Widget object){
		if(object instanceof AbsolutePanel){
			return new AbsolutePanelDesigner(this, parent, (AbsolutePanel)object);
		}
		else if(object instanceof FlowPanel){
			return new FlowPanelDesigner(this, parent, (FlowPanel)object);
		}
		else if(object instanceof ScrollPanel){
			return new ScrollPanelDesigner(this, parent, (ScrollPanel)object);
		}
		else if(object instanceof FocusPanel){
			return new FocusPanelDesigner(this, parent, (FocusPanel)object);
		}
		else if(object instanceof CaptionPanel){
			return new CaptionPanelDesigner(this, parent, (CaptionPanel)object);
		}
		else if(object instanceof HorizontalPanel){
			return new HorizontalPanelDesigner(this, parent, (HorizontalPanel)object);
		}
		else if(object instanceof VerticalPanel){
			return new VerticalPanelDesigner(this, parent, (VerticalPanel)object);
		}
		return null;
	}
}
